home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / Documentation / Development Notes / TroubleShooting / Compile⁄Link Errors next >
Encoding:
Text File  |  1996-08-16  |  9.0 KB  |  220 lines  |  [TEXT/ttxt]

  1. OpenDoc
  2. Development
  3. Framework
  4.                                                                                                                                                                                      
  5. Compile/Link Errors 
  6. ODF Release 1                                                                                                                                                             
  7.  
  8.  
  9. Table of Contents
  10. -----------------
  11. • Misuse of Exception Macros
  12. • Misuse of RTTI Macros
  13.  
  14. This document explains some of the compile and link errors you might see due to misuse of Exception and RTTI macros.
  15.  
  16.  
  17. Misuse of Exception Macros
  18.  
  19. Consider the following code:
  20.  
  21. class X
  22. {
  23. public:
  24.     FW_DECLARE_AUTO(X)
  25. public:
  26.     X();
  27.     ~X();
  28. };
  29.  
  30. FW_DEFINE_AUTO(X)
  31.  
  32. X::X()
  33. {
  34.     FW_END_CONSTRUCTOR
  35. }
  36.  
  37. X::~X()
  38. {
  39.     FW_START_DESTRUCTOR
  40. }
  41.  
  42. void foo()
  43. {
  44.     X x1;
  45. }
  46.  
  47. The above code correctly uses the four required macros to make class X be an AutoDestruct class.  In the examples that follow, we show the compile or link errors that appear if we "forget" or misuse one or more of the macros.  The error messages are those emitted by Metrowerks Codewarrior, but other compilers will emit similar errors.
  48.  
  49. 1) Omit the FW_DECLARE_AUTO macro
  50.  
  51. Warning : function has no prototype
  52. Part.cpp line 115   char* FW_PrivGetAutoName(const X*) { return "X"; }  extern FW_PrivDestroyProc FW_PrivGetDestroyProc(const X*); extern FW_Pri
  53. Error   : '__dl' is not a struct/union/class member
  54. Part.cpp line 115   r((X*) self); } static void FW_PrivStaticDeleterX(void* p) { X::operator delete(p); } } FW_PrivDestroyProc FW_PrivGetDestroyPr
  55.  
  56. The FW_DECLARE_AUTO declares some functions that are defined by the FW_DEFINE_AUTO macro.   If the FW_DECLARE_AUTO macro is omitted, the compiler will emit errors when the FW_DEFINE_AUTO macro is compiled.
  57.  
  58. 2) Omit the FW_DEFINE_AUTO macro
  59.  
  60. Link Error   : undefined ‘X::operator delete(void*)’ (code)
  61. Referenced from ‘X::~X()’ in Part.cpp
  62. Link Error   : undefined ‘FW_PrivGetDestroyProc(constX*)’ (code)
  63. Referenced from ‘X::~X()’ in Part.cpp
  64. Referenced from ‘X::X()’ in Part.cpp
  65. Link Error   : undefined ‘FW_PrivGetAutoName(constX*)’ (code)
  66. Referenced from ‘X::~X()’ in Part.cpp
  67. Referenced from ‘X::X()’ in Part.cpp
  68.  
  69. This is the reverse of case 1). Here, we assume the FW_DECLARE_AUTO macro is present, but the FW_DEFINE_AUTO macro is missing.  In this case, some functions are declared, but never defined, so the error isn't detected until link time.
  70.  
  71. 3) Omit both the FW_DECLARE_AUTO and FW_DEFINE_AUTO macros
  72.  
  73. Link Error   : undefined ‘FW_PrivGetDestroyProc<1X>(constX*)’ (code)
  74. Referenced from ‘X::~X()’ in Part.cpp
  75. Referenced from ‘X::X()’ in Part.cpp
  76. Link Error   : undefined ‘FW_PrivGetAutoName<1X>(constX*)’ (code)
  77. Referenced from ‘X::~X()’ in Part.cpp
  78. Referenced from ‘X::X()’ in Part.cpp
  79.  
  80. If you forget both the FW_DECLARE_AUTO and the FW_DEFINE_AUTO macros for a class, but then use the FW_END_CONSTRUCTOR and/or FW_START_DESTRUCTOR, you will get link errors like the above.  These errors are not detected until compile time because the two functions shown are declared as template functions, but the implementations for the templates are created only through the FW_DEFINE_AUTO macro.
  81.  
  82. 4) Private FW_DECLARE_AUTO
  83.  
  84. This is a more subtle problem.  Suppose you declared your class like this:
  85.  
  86. class X
  87. {
  88.     FW_DECLARE_AUTO(X)
  89. public:
  90.     X();
  91.     ~X();
  92. };
  93.  
  94. Since members of classes are private by default, the member functions defined by the FW_DECLARE_AUTO macro above will be private.  This will result in errors like the following:
  95.  
  96. Error   : illegal access to protected/private member
  97. Part.cpp line 115   r((X*) self); } static void FW_PrivStaticDeleterX(void* p) { X::operator delete(p); } } FW_PrivDestroyProc FW_PrivGetDestroyPr
  98.  
  99. 5) Neglect to use FW_NEW
  100.  
  101. Suppose that the function foo() above allocated an instance of class X using new, like this:
  102.  
  103. void foo()
  104. {
  105.     X* x1 = new X;
  106. }
  107.  
  108. Dynamically allocated AutoDestruct objects must be allocated with FW_NEW.  If you forget and use regular operator new instead, you'll get a compile time error:
  109.  
  110. Error   : illegal access to protected/private member
  111. Part.cpp line 130   X* x2 = new X();
  112.  
  113. This error happens because the FW_DECLARE_AUTO macro declares the standard operator new to be private.
  114.  
  115. 6) Use FW_NEW on a non-AutoDestruct object
  116.  
  117. Once you get in the habit of using FW_NEW, it's easy to make the mistake of using FW_NEW on a non-AutoDestruct object.  For example, assume class Y is not an AutoDestruct object, and you write something like this:
  118.  
  119. void foo()
  120. {
  121.     Y* y = FW_NEW(Y, ());
  122. }
  123.  
  124. You should then seen a compile error like this:
  125.  
  126. Error   : function call '__nw(unsigned long, FW_CPrivWatcher)' does not match
  127. '__nw(unsigned long)'
  128. '__nw(unsigned long, void *)'
  129. Part.cpp line 135   (Y*) ( new(FW_CPrivWatcher(FW_PrivGetDeleteProc((const Y*)0))) Y(), FW_PrivWatcher_Pop() )
  130.  
  131. This is because FW_NEW uses a overloaded variant of operator new that is only defined by the FW_DECLARE_AUTO macro.
  132.  
  133. 7) Use FW_DEFINE_AUTO twice for the same class
  134.  
  135. Sometimes it's convient to create a new class by copying code from another class and then renaming.  If you do this by hand and forget to rename the class in the FW_DEFINE_AUTO macro, you'll be invoking the FW_DEFINE_AUTO macro twice for the same class.  This will show up as a compile time error if both instances of the macro are in the same .cpp file, or as a link-time error if they are in separate .cpp files.
  136.  
  137. 8) Use FW_DEFINE_AUTO where a FW_DECLARE_AUTO should be used
  138.  
  139. Suppose you use the FW_DEFINE_AUTO macro in the class declaration by mistake.  This will cause a whole series of errors, beginning with these:
  140.  
  141. Error   : illegal struct/union/enum/class definition
  142. Part.cpp line 113   char* FW_PrivGetAutoName(const X*) { return "X"; }  extern FW_PrivDestroyProc FW_PrivGetDestroyProc(const X*); extern FW_Priv
  143. Error   : declaration syntax error
  144. Part.cpp line 114   public:
  145. Error   : declaration syntax error
  146. Part.cpp line 115   X();
  147. Error   : declaration syntax error
  148. Part.cpp line 116   ~X();
  149. Error   : declaration syntax error
  150. Part.cpp line 117   };
  151.  
  152. 9) Use FW_DECLARE_AUTO where a FW_DEFINE_AUTO should be used
  153.  
  154. Suppose you use the FW_DECLARE_AUTO macro in the .cpp file by mistake.  This will cause at least one compile-time error:
  155.  
  156. Error   : declaration syntax error
  157. Part.cpp line 119   friend char* FW_PrivGetAutoName(const X*); friend FW_PrivDestroyProc FW_PrivGetDestroyProc(const X*); friend FW_PrivDeletePro
  158.  
  159.  
  160.  
  161. Misuse of RTTI Macros
  162.  
  163. Consider the following code:
  164.  
  165. class A
  166. {
  167. public:
  168.     FW_DECLARE_CLASS
  169. public:
  170.     A() {}
  171.     virtual ~A() {}
  172. };
  173.  
  174. class B : public A
  175. {
  176. public:
  177.     FW_DECLARE_CLASS
  178. public:
  179.     B() {}
  180.     virtual ~B() {}
  181. };
  182.  
  183. FW_DEFINE_CLASS_M0(A)
  184. FW_DEFINE_CLASS_M1(B, A)
  185.  
  186. void foo()
  187. {
  188.     A* a = new B();
  189.     B* b = FW_DYNAMIC_CAST(B, a);
  190. }
  191.  
  192. The above code correctly uses the FW_DECLARE_CLASS and FW_DEFINE_CLASS_Mn macros required to make classes have runtime type identification.  In the examples that follow, we show the compile or link errors that appear if we "forget" or misuse one or more of the macros.  The error messages are those emitted by Metrowerks Codewarrior, but other compilers will emit similar errors.
  193.  
  194. 1) Omit FW_DECLARE_CLASS
  195.  
  196. Suppose we left out the FW_DECLARE_CLASS macro for class A. We'd then get these compile-time errors:
  197.  
  198. Error   : 'gAncestors' is not a struct/union/class member
  199. Part.cpp line 124   const FW_SClassInfoPtr A::gAncestors[] = { 0 }; const size_t A::gAncestorOffsets[] = { 0 }; FW_SClassInfo A::gClassInfo = 
  200. Error   : 'gClassInfo' is not a struct/union/class member
  201. Part.cpp line 125   const FW_SClassInfoPtr B::gAncestors[] = { (&A::gClassInfo), 0 }; const size_t B::gAncestorOffsets[] = { (((char*)((A*)((
  202. Error   : 'PrivVirtualGetClassInfo' is not a struct/union/class member
  203. Part.cpp line 1   
  204.  
  205. FW_DECLARE_CLASS macro declares some static data members and a virtual function.  If you forget the FW_DECLARE_CLASS macro but use the FW_DEFINE_CLASS_Mn macro, the compiler emit errors for the references to undeclared data and functions.
  206.  
  207. 2) Omit FW_DEFINE_CLASS_Mn
  208.  
  209. Suppose we left out the FW_DEFINE_CLASS_M0 macro for class A. We'd then get the following link-time errors:
  210.  
  211. Link Error   : undefined ‘A::gClassInfo’ (data)
  212. Referenced from ‘FW_PrivStaticGetClassInfo<1A>(A*)’ in Part.cpp
  213. Referenced from ‘B::gAncestors’ in Part.cpp
  214. Link Error   : missing vtable ‘A::__vt’
  215. Check that all virtual functions and static members are defined
  216.  
  217. In this case, the members are declared but never defined (implemented), so the error doesn't show up until link time.  Note in particular the last link error. Many C++ compilers generated the vtable for a class in the translation unit that implements the first virtual function declared for the class. Since by convention, we normally place the FW_DECLARE_CLASS macro at the top of the class declaration, the virtual function declared by the FW_DECLARE_CLASS macro is the first virtual function.  Since it isn't implemented, the compiler doesn't generate the vtable; hence the error "missing vtable ‘A::__vt’".
  218.  
  219. © 1993 - 1996 Apple Computer, Inc. All rights reserved.
  220. Apple, the Apple Logo, Macintosh, and OpenDoc are trademarks of Apple Computer, Inc., registered in the United States and other countries.